package com.huawei.esdk.tpoa.business.oa.sitemgr;

import java.util.ArrayList;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.log4j.Logger;
import com.huawei.esdk.platform.common.SDKErrorCode;
import com.huawei.esdk.platform.common.ThreadLocalHolder;
import com.huawei.esdk.platform.common.config.ConfigManager;
import com.huawei.esdk.platform.common.exception.SDKException;
import com.huawei.esdk.platform.common.utils.DateUtils;
import com.huawei.esdk.platform.common.utils.DurationUtils;
import com.huawei.esdk.platform.common.utils.StringUtils;
import com.huawei.esdk.tp.common.constants.InfoKeys;
import com.huawei.esdk.tp.domain.model.Site;
import com.huawei.esdk.tp.domain.model.bean.DateTimeRange;
import com.huawei.esdk.tp.domain.model.bean.FreeBusyInfo;
import com.huawei.esdk.tp.domain.model.bean.SiteFreeBusyRes;
import com.huawei.esdk.tpoa.business.oa.mapping.TPOADataMapping;

public class TPOASiteSynchronization implements Runnable
{
    //会场领域bean
    private Site site = new Site();
    
    //待刷新的会场
    private List<String> siteUris = new ArrayList<String>();
    
    //同步时长
    private String syncSitesTimeSpan;
    
    //时间段
    private DateTimeRange timeRange;
    
    //会场同步处理类
    private TPOASiteSynchronizationHandler handler;
    
    //初次查询的会场忙闲状态
    private List<Site> currSiteStatus = new ArrayList<Site>();
    
    private  Date currentUTCDate = DateUtils.toDate(DateUtils.getCurrentUTCTime());
    
    private static final Logger LOGGER = Logger.getLogger(TPOASiteSynchronization.class);
    
    public void init()
        throws SDKException
    {
        for (Entry<String, String> entry : TPOADataMapping.siteUriMapping.entrySet())
        {
            siteUris.add(entry.getValue());
        }
        
        timeRange = new DateTimeRange();
        
        handler = new TPOASiteSynchronizationHandler();
        
        syncSitesTimeSpan = ConfigManager.getInstance().getValue("tpoa_syncSites_timeSpan");
        if ("".equals(syncSitesTimeSpan))
        {
            syncSitesTimeSpan = "P365D";
        }

    }
    
    @Override
    public void run()
    {
        //启动时获取上次本eSDK创建的会议
        int exchangeQueryRange = DurationUtils.durationStr2int(syncSitesTimeSpan) / 60;
        try
        {
            handler.restoreInitialValue(DateUtils.toDate(DateUtils.getCurrentUTCTime()), exchangeQueryRange);
        }
        catch (SDKException e1)
        {
            LOGGER.error("restoreInitialValue exchange conf failed", e1);
        }
        
        int syncSitesTimeInterval = 60;
        String syncSitesTimeIntervalStr = ConfigManager.getInstance().getValue("tpoa_syncSites_timeInterval");
        if (!StringUtils.isEmpty(syncSitesTimeIntervalStr))
        {
            try
            {
                syncSitesTimeInterval = Integer.parseInt(syncSitesTimeIntervalStr);
            }
            catch (NumberFormatException e)
            {
                LOGGER.error("NumberFormatException for syncSitesTimeInterval,set default value 60", e);
                syncSitesTimeInterval = 60;
            }
        }
        
        // 查询全部
        try
        {
            querySiteFreeBusy();
        }
        catch(Exception e)
        {
            LOGGER.error("synchronize exchange site failed", e);
        }
        
        int count = 0;
        while (true)
        {
            try
            {
                //每三十秒获取一下SMC上的会场状态
                Thread.sleep(50);
                count++;
                if (count > syncSitesTimeInterval*20)
                {
                    count = 0;
                    //增量查询
                    synchSiteFreeBusy();
                }
                
            }
            catch (Exception e)
            {
                LOGGER.error("synchronize exchange site failed", e);
            }
        }
        
    }
    
    private void querySiteFreeBusy() throws SDKException, InterruptedException
    {
        LOGGER.info("begin to update Exchange Site freeBusyInfo");
        //调用领域层的querySiteFreeBusy接口，获取SMC会场 状态
        ThreadLocalHolder.get().getEntities().put(InfoKeys.SDK_SESSION_ID.toString(), "");
        
        timeRange.setStart(currentUTCDate);
        timeRange.setSpan(syncSitesTimeSpan);
        SiteFreeBusyRes queryResult = querySiteFreeBusyGradually(false);
        
        //调用会场同步处理器，更新exchange的会场状态
        if (0 == queryResult.getResult().getErrCode())
        {
            currSiteStatus = queryResult.getSiteFreeBusyStateList();
            handler.updateExchangeSiteFreeBusyInfo(currSiteStatus, timeRange.getStart());
        }
    }
    
    private void synchSiteFreeBusy() throws SDKException, InterruptedException
    {
        LOGGER.info("begin to update Exchange Site freeBusyInfo");
        //调用领域层的querySiteFreeBusy接口，获取SMC会场 状态
        ThreadLocalHolder.get().getEntities().put(InfoKeys.SDK_SESSION_ID.toString(), "");
        
        SiteFreeBusyRes queryResult = querySiteFreeBusyGradually(true);
        if (0 == queryResult.getResult().getErrCode())
        {
            if(0 < queryResult.getSiteFreeBusyStateList().size())
            {
                timeRange.setStart(currentUTCDate);
            }
            updateCurrSiteStatus(queryResult.getSiteFreeBusyStateList());
            handler.updateExchangeSiteFreeBusyInfo(currSiteStatus, timeRange.getStart());
        }
    }
    
    private void updateCurrSiteStatus(List<Site> fressBusyInfos)
    {
        if(0 == fressBusyInfos.size())
        {
            return;
        }
        
        Map<String, List<FreeBusyInfo>> freeBusyInfoMap = new LinkedHashMap<String, List<FreeBusyInfo>>();
        for(Site siteInfo : currSiteStatus)
        {
            if(null != siteInfo.getFreeBusyInfoList())
            {
                freeBusyInfoMap.put(siteInfo.getUri(), siteInfo.getFreeBusyInfoList());
            }
        }
        
        
        for(Site siteInfo : fressBusyInfos)
        {
            if(freeBusyInfoMap.containsKey(siteInfo.getUri()))
            {
                Map<String, FreeBusyInfo> synchfreeBusyMap = new LinkedHashMap<String, FreeBusyInfo>();
                Map<String, FreeBusyInfo> freeBusyMap = new LinkedHashMap<String, FreeBusyInfo>();
                for(FreeBusyInfo freeBusyInfo : siteInfo.getFreeBusyInfoList())
                {
                    synchfreeBusyMap.put(freeBusyInfo.getConfInternalId(), freeBusyInfo);
                }
                for(FreeBusyInfo freeBusyInfo : freeBusyInfoMap.get(siteInfo.getUri()))
                {
                    freeBusyMap.put(freeBusyInfo.getConfInternalId(), freeBusyInfo);
                }
                
                for(Entry<String, FreeBusyInfo> synchfreeBusy : synchfreeBusyMap.entrySet())
                {
                    if("busy".equalsIgnoreCase(synchfreeBusy.getValue().getFreeBusyState()))
                    {
                        freeBusyMap.put(synchfreeBusy.getKey(), synchfreeBusy.getValue());
                    }
                    else if("free".equalsIgnoreCase(synchfreeBusy.getValue().getFreeBusyState()))
                    {
                        freeBusyMap.remove(synchfreeBusy.getKey());
                    }
                }
                
                
                List<FreeBusyInfo> tempDate = new ArrayList<FreeBusyInfo>();
                for(Entry<String, FreeBusyInfo> item : freeBusyMap.entrySet())
                {
                    tempDate.add(item.getValue());
                }
                freeBusyInfoMap.put(siteInfo.getUri(), tempDate);
            }
            else
            {
                freeBusyInfoMap.put(siteInfo.getUri(), siteInfo.getFreeBusyInfoList());
            }

        }
        
        currSiteStatus.clear();
        for(Entry<String, List<FreeBusyInfo>> item : freeBusyInfoMap.entrySet())
        {
            Site site = new Site();
            site.setUri(item.getKey());
            site.setFreeBusyInfoList(item.getValue());
            currSiteStatus.add(site); 
        }
    }

    private SiteFreeBusyRes querySiteFreeBusyGradually(boolean isSync) throws SDKException, InterruptedException
    {
        currentUTCDate = DateUtils.toDate(DateUtils.getCurrentUTCTime());
        
        int numberPerPage = 50;
        String numberPerPageStr = null;
        if(isSync)
        {
            numberPerPageStr = ConfigManager.getInstance().getValue("tpoa_synchAllSitesFreeBusy_numberPerPage");
        }
        else
        {
            numberPerPageStr = ConfigManager.getInstance().getValue("tpoa_queryAllSitesFreeBusy_numberPerPage");
        }
        
        if (!StringUtils.isEmpty(numberPerPageStr))
        {
            try
            {
                numberPerPage = Integer.parseInt(numberPerPageStr);
            }
            catch (NumberFormatException e)
            {
                LOGGER.error("NumberFormatException for numberPerPageStr,set default value 50", e);
                numberPerPage = 50;
            }
        }
        
        int pageNum = 0 == siteUris.size()%numberPerPage ?
            siteUris.size()/numberPerPage : siteUris.size()/numberPerPage+1;
        
        SiteFreeBusyRes queryResult = new SiteFreeBusyRes();
        SDKErrorCode result = new SDKErrorCode();
        result.setErrCode(0);
        queryResult.setResult(result);
        
        for(int i = 0; i < pageNum; i++)
        {
            List<String> urisTemp = new ArrayList<String>();
            for(int j = i * numberPerPage;
                j < (i + 1) * numberPerPage && j < siteUris.size();
                j++)
            {
                urisTemp.add(siteUris.get(j));
            }
            
            SiteFreeBusyRes queryResultTemp = null;
            if(isSync)
            {
                queryResultTemp = site.synchSiteFreeBusy(urisTemp, timeRange);
            }
            else
            {
                queryResultTemp = site.querySiteFreeBusy(urisTemp, timeRange);
            }
           
            if(null != queryResultTemp &&
                0 == queryResultTemp.getResult().getErrCode())
            {
                queryResult.getSiteFreeBusyStateList()
                .addAll(queryResultTemp.getSiteFreeBusyStateList());
            }
            
            Thread.sleep(5*1000);
        }
        
        
        return queryResult;
    }
}